package com.dyt.itool.generator;

import com.dyt.itool.model.IProperty;
import com.dyt.itool.model.impl.BasicProperty;
import com.dyt.itool.model.impl.ListProperty;

import java.util.HashMap;
import java.util.Map;


public class TypeScriptHelper {


    public static final String NEWLINE = "\r";

    private Map<String, String> basicType = new HashMap<String, String>();
    private Map<String, String> basicWrapType = new HashMap<String, String>();


    public TypeScriptHelper() {
        basicType.put("bool", "boolean");
        basicType.put("byte", "number");
        basicType.put("short", "number");
        basicType.put("int", "number");
        basicType.put("long", "number");
        basicType.put("float", "number");
        basicType.put("double", "number");
        basicType.put("string", "string");

        basicWrapType.put("bool", "Boolean");
        basicWrapType.put("byte", "Byte");
        basicWrapType.put("short", "Short");
        basicWrapType.put("int", "Int");
        basicWrapType.put("long", "Long");
        basicWrapType.put("float", "Float");
        basicWrapType.put("double", "Double");
        basicWrapType.put("string", "String");
    }

    public String getTSType(IProperty property) {
        if (property.getType() == IProperty.PropertyType.BASIC) {
            return basicType.get(property.getTypeName());
        } else if (property.getType() == IProperty.PropertyType.LIST) {
            String name = property.getTypeName();
            name = name.replaceFirst("list", "Array");

            String tmpName = name.substring(name.indexOf("<") + 1, name.length() - 1);
            if (basicType.containsKey(tmpName)) {
                name = name.replaceFirst(tmpName, basicType.get(tmpName));
            }
            return name;
        } else {
            return property.getTypeName();
        }
    }

    public String getDefaultValue(IProperty property) {

        if (property.getType() == IProperty.PropertyType.BASIC) {
            BasicProperty basicProperty = (BasicProperty) property;
            if ("string".equalsIgnoreCase(basicProperty.getTypeName())) {
                return "\"\"";
            } else if ("bool".equalsIgnoreCase(basicProperty.getTypeName())) {
                return "false";
            } else {
                return "0";
            }
        } else if (property.getType() == IProperty.PropertyType.USERTYPE) {
            return "new " + property.getTypeName() + "()";
        } else if (property.getType() == IProperty.PropertyType.LIST) {
            return "[]";
        } else {
            return "null";
        }

    }

    public String getReadString(IProperty property) {

        if (property.getType() == IProperty.PropertyType.USERTYPE) {

            StringBuilder sb = new StringBuilder();
            sb.append("        if (buffer.readBoolean()) {");
            sb.append(NEWLINE);
            sb.append("            this." + property.getVarName() + ".readFromBuffer(buffer);");
            sb.append(NEWLINE);
            sb.append("        } else {");
            sb.append(NEWLINE);
            sb.append("            this." + property.getVarName() + " = null;");
            sb.append(NEWLINE);
            sb.append("        }");
            sb.append(NEWLINE);
            return sb.toString();


        } else if (property.getType() == IProperty.PropertyType.LIST) {

            ListProperty listProperty = (ListProperty) property;

            StringBuilder sb = new StringBuilder();
            sb.append("        {");
            sb.append(NEWLINE);
            sb.append("            var size = buffer.readInt();");
            sb.append(NEWLINE);
            sb.append("            for (var i = 0; i < size; i++) {");
            sb.append(NEWLINE);
            if (listProperty.getElementType().getType() == IProperty.PropertyType.BASIC) {
                sb.append("                this." + property.getVarName() + ".push(buffer." + getReadString(listProperty.getElementType().getTypeName()) + "());");
            } else {
                sb.append("                var " + property.getVarName() + "Model: " + listProperty.getElementType().getTypeName() + " = new " + listProperty.getElementType().getTypeName() + "();");
                sb.append(NEWLINE);
                sb.append("                " + property.getVarName() + "Model.readFromBuffer(buffer);");
                sb.append(NEWLINE);
                sb.append("                this." + property.getVarName() + ".push(" + property.getVarName() + "Model);");
            }
            sb.append(NEWLINE);
            sb.append("            }");
            sb.append(NEWLINE);
            sb.append("        }");
            return sb.toString();

        } else if (property.getType() == IProperty.PropertyType.BASIC && property.getTypeName().equals("long")) {

            StringBuilder sb = new StringBuilder();
            sb.append("        {");
            sb.append(NEWLINE);
            sb.append("                var num: number = 0;");
            sb.append(NEWLINE);
            sb.append("                for(var i = 0; i < 8; i++) {");
            sb.append(NEWLINE);
            sb.append("                        num = num << 8 | buffer.readByte() & 0xff;");
            sb.append(NEWLINE);
            sb.append("                }");
            sb.append(NEWLINE);
            sb.append("                this." + property.getVarName() + " = num;");
            sb.append(NEWLINE);
            sb.append("        }");
            return sb.toString();

        } else {

            return "        this." + property.getVarName() + " = buffer." + getReadString(property.getTypeName()) + "();";

        }

    }


    public String getWriteString(IProperty property) {


        if (property.getType() == IProperty.PropertyType.USERTYPE) {

            StringBuilder sb = new StringBuilder();
            sb.append("        if (this." + property.getVarName() + " != null) {");
            sb.append(NEWLINE);
            sb.append("            buffer.writeBoolean(true);");
            sb.append(NEWLINE);
            sb.append("            this." + property.getVarName() + ".writeToBuffer(buffer);");
            sb.append(NEWLINE);
            sb.append("        } else {");
            sb.append(NEWLINE);
            sb.append("            buffer.writeBoolean(false);");
            sb.append(NEWLINE);
            sb.append("        }");
            sb.append(NEWLINE);
            return sb.toString();

        } else if (property.getType() == IProperty.PropertyType.LIST) {

            ListProperty listProperty = (ListProperty) property;

            StringBuilder sb = new StringBuilder();
            sb.append("        {");
            sb.append(NEWLINE);
            sb.append("            var size = this." + property.getVarName() + ".length;");
            sb.append(NEWLINE);
            sb.append("            buffer.writeInt(size);");
            sb.append(NEWLINE);
            sb.append("            for (var i = 0; i < size; i++) {");
            sb.append(NEWLINE);
            if (listProperty.getElementType().getType() == IProperty.PropertyType.BASIC) {
                sb.append("                buffer." + getWriteString(listProperty.getElementType().getTypeName()) + "(this." + property.getVarName() + "[i]);");
                sb.append(NEWLINE);
            } else {
                sb.append("                var " + property.getVarName() + "Model = this." + property.getVarName() + "[i];");
                sb.append(NEWLINE);
                sb.append("                " + property.getVarName() + "Model.writeToBuffer(buffer);");
                sb.append(NEWLINE);
            }
            sb.append("            }");
            sb.append(NEWLINE);
            sb.append("        }");
            return sb.toString();

        } else if (property.getType() == IProperty.PropertyType.BASIC && property.getTypeName().equals("long")) {

            StringBuilder sb = new StringBuilder();
            sb.append("        {");
            sb.append(NEWLINE);
            sb.append("                buffer.writeByte((0xff00000000000000 & this." + property.getVarName() + ") >> 56);");
            sb.append(NEWLINE);
            sb.append("                buffer.writeByte((0xff000000000000 & this." + property.getVarName() + ") >> 48);");
            sb.append(NEWLINE);
            sb.append("                buffer.writeByte((0xff0000000000 & this." + property.getVarName() + ") >> 40);");
            sb.append(NEWLINE);
            sb.append("                buffer.writeByte((0xff00000000 & this." + property.getVarName() + ") >> 32);");
            sb.append(NEWLINE);
            sb.append("                buffer.writeByte((0xff000000 & this." + property.getVarName() + ") >> 24);");
            sb.append(NEWLINE);
            sb.append("                buffer.writeByte((0xff0000 & this." + property.getVarName() + ") >> 16);");
            sb.append(NEWLINE);
            sb.append("                buffer.writeByte((0xff00 & this." + property.getVarName() + ") >> 8);");
            sb.append(NEWLINE);
            sb.append("                buffer.writeByte(0xff & this." + property.getVarName() + "); ");
            sb.append(NEWLINE);
            sb.append("        }");
            return sb.toString();

        } else {

            return "        buffer." + getWriteString(property.getTypeName()) + "(this." + property.getVarName() + ");";
        }
    }


    private String getReadString(String basicType) {
        return getIoString("read", basicType);
    }

    private String getWriteString(String basicType) {
        return getIoString("write", basicType);
    }


    public String getIoString(String suffix, String basicType) {
        if ("string".equals(basicType)) {
            suffix += "UTF";
        } else {
//			char[] chars =  basicType.toCharArray();
//			chars[ 0 ] = Character.toUpperCase( chars[ 0 ] );
            suffix += basicWrapType.get(basicType);
        }
        return suffix;
    }


}
